//***************************************************************************
//*
//*	File:			StringEx.h
//*	Description:	Adds some methods to CString
//*
//***************************************************************************

//
//--------------------------------------------------------------- PRECOMPILED
//

#include "stdafx.h"

//
//--------------------------------------------------- DECLARATION DEPENDENCIES
//

//
//--------------------------------------------------------------- DECLARATION
//

#include "StringEx.h"

//
//--------------------------------------------------- DEFINITION DEPENDENCIES
//

//
//-------------------------------------------------------------- PREPROCESSOR
//

#ifdef	_DEBUG
#define new DEBUG_NEW
#undef	THIS_FILE
static	char THIS_FILE[] = __FILE__;
#endif

//
//---------------------------------------------------------------- DEFINITION
//

/*
static g_Test()
{
	CString		str;
	CStringEx	strEx;

	strEx = str;
	str = strEx;

	strEx.FindNoCase( strEx );
};
*/

//
//---------------------------------------------------------------------------------------------------
//*************************************     CON/DESTRUCTION     *************************************
//---------------------------------------------------------------------------------------------------
//

//***************************************************************************************************
//**																					  Constructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Copy constructor
//**	@END
//***************************************************************************************************
//inline
CStringEx::CStringEx( const CStringEx& a_strText )
: CString( a_strText )
{}

//***************************************************************************************************
//**																					  Constructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Assignment constructor
//**	@END
//***************************************************************************************************
//inline
CStringEx::CStringEx( const CString& a_strText )
: CString( a_strText )
{}

//***************************************************************************************************
//**																					  Constructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Assignment constructor
//**	@END
//***************************************************************************************************
//inline
CStringEx::CStringEx( const UCHAR a_pchText )
: CString( a_pchText )
{}

//***************************************************************************************************
//**																					  Constructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Assignment constructor
//**	@END
//***************************************************************************************************
//inline
CStringEx::CStringEx( LPCWSTR a_pchText )
: CString( a_pchText )
{}

//***************************************************************************************************
//**																					  Constructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Assignment constructor
//**	@END
//***************************************************************************************************
//inline
CStringEx::CStringEx( LPCSTR a_pchText )
: CString( a_pchText )
{}

//***************************************************************************************************
//**																					  Constructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Assignment constructor
//**	@END
//***************************************************************************************************
//inline
CStringEx::CStringEx( LPCSTR a_pchText, int a_iLength )
: CString( a_pchText, a_iLength )
{}

//***************************************************************************************************
//**																					  Constructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Assignment constructor
//**	@END
//***************************************************************************************************
//inline
CStringEx::CStringEx( TCHAR a_chChar, int a_iRepeat )
: CString( a_chChar, a_iRepeat )
{}

//***************************************************************************************************
//**																					  Constructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Default constructor
//**	@END
//***************************************************************************************************
//inline
CStringEx::CStringEx()
: CString()
{}

//
//---------------------------------------------------------------------------------------------------
//******************************************     FIND     *******************************************
//---------------------------------------------------------------------------------------------------
//

//***************************************************************************************************
//**																					   FindNoCase
//***************************************************************************************************
//**	@DOC		FIND
//**	@MFUNC		Finds the specified text while ignoring case
//**	@PARM		[in] The string to find
//**	@PARM		[in] The index of the first character to compare
//**	@RDESC		The index of the first matching character
//**	@END
//***************************************************************************************************
//inline
int CStringEx::FindNoCase( const CString& a_strText, int a_iStart /*= 0*/ ) const 
{
	//
	//	CONVERT TO LOWER CASE
	//
	CString strSrc( *this		);	strSrc.MakeLower();
	CString strDst( a_strText	);	strDst.MakeLower();

	//
	//	FIND IN LOWER CASE
	//
	return strSrc.Find( strDst, a_iStart );
}

//***************************************************************************************************
//**																					 FindAllCases
//***************************************************************************************************
//**	@DOC		FIND
//**	@MFUNC		Finds the specified text or it's upper or lower case representation
//**	@PARM		[in] The index of the first character to compare
//**	@PARM		[in] The string to find
//**	@PARM		[out] Address of a flag to set when the match was lower-case
//**	@PARM		[out] Address of a flag to set when the match was upper-case
//**	@RDESC		The index of the first matching character
//**	@END
//***************************************************************************************************
//inline
int CStringEx::FindAllCases( const CString& a_strText, int a_iStart /*= 0*/, BOOL* a_pbIsUpper /*= NULL*/, BOOL* a_pbIsLower /*= NULL*/ ) const 
{
	CString strTemp( a_strText ); 

	//
	//	FIND AS-IS
	//
	int  iPos = 0;
	
	if ( (iPos = this->Find( strTemp, a_iStart )) >= 0 )
	{
		if ( NULL != a_pbIsLower ) *a_pbIsLower = FALSE;
		if ( NULL != a_pbIsUpper ) *a_pbIsLower = FALSE;

		return iPos;
	}

	//
	//	FIND UPPER CASE
	//
	strTemp.MakeUpper();

	if ( (iPos = this->Find( strTemp, a_iStart )) >= 0 )
	{
		if ( NULL != a_pbIsLower ) *a_pbIsLower = FALSE;
		if ( NULL != a_pbIsUpper ) *a_pbIsLower = TRUE;

		return iPos;
	}

	//
	//	FIND LOWER CASE
	//
	strTemp.MakeLower();

	if ( (iPos = this->Find( strTemp, a_iStart )) >= 0 )
	{
		if ( NULL != a_pbIsLower ) *a_pbIsLower = FALSE;
		if ( NULL != a_pbIsUpper ) *a_pbIsLower = TRUE;

		return iPos;
	}

	//
	//	NO MATCH
	//
	return -1;
}

//***************************************************************************************************
//**																					ReplaceNoCase
//***************************************************************************************************
//**	@DOC		FIND
//**	@MFUNC		Replaces all instances of the find string with the replace string while ignoring 
//**				the case of the find string
//**	@PARM		[in] The string to find
//**	@PARM		[in] The string to replace with
//**	@RDESC		The number of replacements made
//**	@END
//***************************************************************************************************
//inline
int CStringEx::ReplaceNoCase( const CString& a_strFind, const CString& a_strReplace ) 
{
	int iPos = 0;
	int iCnt = 0;

	//
	//	WHILE THERE ARE MATCHES
	//
	while ( ( iPos = this->FindNoCase( a_strFind, iPos ) ) >= 0 )
	{
		//
		//	REPLACE MATCH
		//
		int iLen = a_strFind.GetLength();
		
		for ( int iCur = 0; iCur < iLen; iCur++ )
		{
			this->SetAt( iCur + iPos, a_strReplace[ iCur ] );
		}

		//
		//	INCREASE COUNT
		//
		++iCnt;
	}

	//
	//	RETURN COUNT
	//
	return iCnt;
}

//***************************************************************************************************
//**																				  ReplaceAllCases
//***************************************************************************************************
//**	@DOC		FIND
//**	@MFUNC		Replaces all instances of the find string with the replace string for each case 
//**				(as-is, lower and upper)
//**	@PARM		[in] The string to find
//**	@PARM		[in] The string to replace with
//**	@RDESC		The number of replacements made
//**	@END
//***************************************************************************************************
//inline
int CStringEx::ReplaceAllCases( const CString& a_strFind, const CString& a_strReplace ) 
{
	CString strFind		( a_strFind		); 
	CString strReplace	( a_strReplace	); 
	int		iCnt		= 0;

	iCnt += this->Replace( strFind, strReplace );	strFind.MakeLower(); strReplace.MakeLower();
	iCnt += this->Replace( strFind, strReplace );	strFind.MakeUpper(); strReplace.MakeUpper();
	iCnt += this->Replace( strFind, strReplace );

	return iCnt;
}

//***************************************************************************************************
//***************************************************************************************************

/*
//***************************************************************************************************
//**																						  Matches
//***************************************************************************************************
//**	@DOC		FIND
//**	@MFUNC		Determines whether the string matches the specifed find string
//**	@PARM		[in] The string to find
//**	@PARM		[in] The find flags. A combination of <t EMatchFlag> values.
//**	@RDESC		<t TRUE> if the string matches, <t FALSE> otherwise.
//**	@END
//***************************************************************************************************
//inline
BOOL CStringEx::Matches( const CString& a_strFind, DWORD a_dwFlags ) const
{
}

//***************************************************************************************************
//**																						ReplaceEx
//***************************************************************************************************
//**	@DOC		FIND
//**	@MFUNC		Finds the specified text 
//**	@PARM		[in] The string to find
//**	@PARM		[in] The find flags. A combination of <t EMatchFlag> values.
//**	@RDESC		The index of the first matching character
//**	@END
//***************************************************************************************************
//inline
int CStringEx::FindEx( const CString& a_strFind, DWORD a_dwFlags ) const
{
}
*/

//***************************************************************************************************
//**																						ReplaceEx
//***************************************************************************************************
//**	@DOC		FIND
//**	@MFUNC		Replaces all instances of the find string with the replace string 
//**	@PARM		[in] The string to find
//**	@PARM		[in] The string to replace with
//**	@PARM		[in] The find flags. A combination of <t EMatchFlag> values.
//**	@RDESC		The number of replacements made
//**	@END
//***************************************************************************************************
//inline
int CStringEx::ReplaceEx( const CString& a_strFind, const CString& a_strReplace, DWORD a_dwFlags ) 
{
	//
	//	SETUP VARS
	//
	BOOL bMatchWord = ( a_dwFlags & EMatchFlag_Word		) ? TRUE : FALSE;
	BOOL bMatchCase = ( a_dwFlags & EMatchFlag_Case		) ? TRUE : FALSE;
	BOOL bAllCases	= ( a_dwFlags & EMatchFlag_AllCases ) ? TRUE : FALSE;
	BOOL bRegExpr	= ( a_dwFlags & EMatchFlag_RegExpr	) ? TRUE : FALSE;
	int	 iReplaced	= 0;

	//
	//	CHECK FOR REGULAR EXPRESSIONS
	//
	if ( TRUE == bRegExpr )
	{
		TRACE0( "CStringEx::ReplaceEx() -> Regular exression are not yet implemented. Sorry.\n" );

		return 0;
	}

	if ( TRUE == bMatchWord ) 
	{
		TRACE0( "CStringEx::ReplaceEx() -> Word matching is not yet implemented. Sorry.\n" );

		return 0;
	}

	//
	//	CHECK CASES
	//
	if ( TRUE == bAllCases  )
	{
		//
		//	ALL CASES
		//
		iReplaced = this->ReplaceAllCases( a_strFind, a_strReplace );
	}
	else 
	{
		//
		//	SINLGE CASE
		//
		if ( FALSE == bMatchCase )		
		{
			//
			//	IGNORE CASE
			//
			iReplaced = this->ReplaceNoCase( a_strFind, a_strReplace );
		}
		else
		{
			//
			//	MATCH CASE
			//
			iReplaced = this->Replace( a_strFind, a_strReplace );
		}
	}

	//
	//	RETURN NUMBER OF REPLACEMENTS MADE
	//
	return iReplaced;
}
